// -*- Mode: Go; indent-tabs-mode: t -*-
//
// Copyright (C) 2018 IOTech Ltd
//
// SPDX-License-Identifier: Apache-2.0

package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net/url"

	mqtt "github.com/eclipse/paho.mqtt.golang"
)

const (
	brokerUrl  = "192.168.0.248"
	brokerPort = 1883
	username   = "admin"
	password   = "public"
)

// var topicSettings string = "edgex/event/mcu/settings"
// var topicRealtime string = "edgex/event/mcu/realtime"
// var topicSpindles string = "edgex/event/mcu/spindles"
var topicCommand string = "edgex/event/mcu/command"
var topicVoltages string = "edgex/event/mcu/voltages"

type McuVoltages_Response struct {
	// MCU 发送的锭子电压数据波形图 MQTT消息内容格式
	Voltages [1000]uint16 `json:"voltages"`
	Ts       string       `json:"ts"`
	Spindle  int          `json:"spindle"`
	Tid      uint64       `json:"tid"` // Command 事务ID
}

type EdgexCmd struct {
	// Edgex 向MCU下发命令的格式  MQTT消息

	// 命令：voltages - 锭子电压数据波形图，命令：settings - MCU配置
	Cmd string `json:"cmd"`

	// 开始 时间戳， 用来判断是否超时
	Ts string `json:"ts"`

	Spindle int    `json:"spindle"` //  Cmd 为 voltages 时的 指定锭号
	Setting string `json:"setting"` //  Cmd 为 settings 时的 指定配置名
	Tid     uint64 `json:"tid"`     //  Cmd 事务ID
	Status  int    `json:"status"`  //
}

var mqttClient *mqtt.Client

func main() {
	var mqttClientId = "Spinning-Device-Test001"
	uri := &url.URL{
		Scheme: "tcp",
		Host:   fmt.Sprintf("%s:%d", brokerUrl, brokerPort),
		User:   url.UserPassword(username, password),
	}

	client, err := createMqttClient(mqttClientId, uri)
	if err != nil {
		fmt.Println(err)
	}

	defer client.Disconnect(5000)
	mqttClient = &client

	token := client.Subscribe(topicCommand, byte(0), onCommandReceivedFromBroker)
	fmt.Println("### Subscribe ###")
	if token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
	}
	select {}
}

func createMqttClient(clientID string, uri *url.URL) (mqtt.Client, error) {
	fmt.Printf("### Create MQTT client and connection: uri=%v clientID=%v ###\n", uri.String(), clientID)
	opts := mqtt.NewClientOptions()
	opts.AddBroker(fmt.Sprintf("%s://%s", uri.Scheme, uri.Host))
	opts.SetClientID(clientID)
	opts.SetUsername(uri.User.Username())
	password, _ := uri.User.Password()
	opts.SetPassword(password)
	opts.SetConnectionLostHandler(func(client mqtt.Client, e error) {
		fmt.Printf("Connection lost : %v", e)
		token := client.Connect()
		if token.Wait() && token.Error() != nil {
			fmt.Printf("Reconnection failed : %v", e)
		} else {
			fmt.Printf("Reconnection sucessful : %v", e)
		}
	})

	client := mqtt.NewClient(opts)
	fmt.Println("### createMqttClient ###")
	token := client.Connect()
	if token.Wait() && token.Error() != nil {
		return client, token.Error()
	}

	return client, nil
}

func onCommandReceivedFromBroker(client mqtt.Client, message mqtt.Message) {

	var edgexCmd = EdgexCmd{}
	err := json.Unmarshal(message.Payload(), &edgexCmd)
	if edgexCmd.Cmd != "voltages" {
		return
	}

	var mcuVoltages = McuVoltages_Response{}
	mcuVoltages.Tid = edgexCmd.Tid
	mcuVoltages.Ts = edgexCmd.Ts
	mcuVoltages.Spindle = edgexCmd.Spindle
	for i := 0; i < len(mcuVoltages.Voltages); i++ {
		mcuVoltages.Voltages[i] = uint16(rand.Uint32())
	}

	jsonData, err := json.Marshal(mcuVoltages)
	if err != nil {
		fmt.Println(err)
	}
	client.Publish(topicVoltages, byte(0), false, jsonData)

	fmt.Printf("### device client.Publish: \n %v ###\n", string(jsonData))

}
